unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Data.DB, DBAccess, MemDS, Uni,System.DateUtils,
  UniProvider, MySQLUniProvider, Vcl.Grids, Vcl.DBGrids, OracleUniProvider,QWorker,utils_locker,
  Vcl.StdCtrls, Vcl.ExtCtrls,RegularExpressions, IdBaseComponent,unidacPool,
  IdComponent, IdTCPConnection, IdTCPClient, IdHTTP,Web.HTTPApp, Vcl.Menus,system.hash,
  System.ImageList, Vcl.ImgList;

type
  TForm1 = class(TForm)
    TrayIcon1: TTrayIcon;
    tmr2: TTimer;
    pm1: TPopupMenu;
    N1: TMenuItem;
    N2: TMenuItem;
    N3: TMenuItem;
    procedure SendSmsTest(TaskName:string);
    procedure SendSmsTestNumber(Number:string);
    procedure FindSuspendedWorker(AJob: PQJob);
    procedure FlushSmsNumberWorker(AJob: PQJob);
    procedure CheckSuspendedList(AJob: PQJob);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure tmr2Timer(Sender: TObject);
    function GetDanHao(str:string):string;
    function GetLastInput: DWORD;
    procedure N1Click(Sender: TObject);
    procedure N3Click(Sender: TObject);
    procedure TrayIcon1DblClick(Sender: TObject);
    //查询流程当前节点
    function SelectAssign(id:string):string;
    //查询流程是否挂起
    function CheckWorkIsSuspended(id:string):Boolean;
    //查询短信接口剩余量
    function QuerySMSNumber:string;
    //查询用户实名
    function SelectUserFid(fid:string):string;
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  FPROCINSTID:TStringList;
  FProcinstidLock:TIocpLocker;
  UniPool: TUniDacAnyPool;

implementation

{$R *.dfm}

function TForm1.GetDanHao(str:string):string;     //RegularExpressions;
var
match: TMatch;
begin
  match := TRegEx.Match(str, '[A-Z]{2,8}[0-9]*');
  if match.Success then //或用一句话 if TRegEx.Match(txt, pattern).Success then
  begin
   Result := match.Value;
  end;
end;

function TForm1.GetLastInput: DWORD; //得到电脑闲置时间
var
  LInput: TLastInputInfo;
  CurrTime: DWORD;
begin
  Result := 0;
  try
    LInput.cbSize := SizeOf(TLastInputInfo);
    GetLastInputInfo(LInput);
    CurrTime := GetTickCount;
      if CurrTime < LInput.dwTime then
        Exit;
    Result := Round((CurrTime - LInput.dwTime) / 1000 / 60);
  except
  end;

end;


procedure TForm1.N1Click(Sender: TObject);
begin
  if not Form1.Showing then
  Form1.Show
  else
  Form1.Hide;
end;

procedure TForm1.N3Click(Sender: TObject);
begin
  Form1.Close;
end;

function TForm1.QuerySMSNumber: string;
var
  HTTP:TIdHTTP;
  ResultStr:TStringList;
  match: TMatch;
begin
  try
     Result := 'Err';
     HTTP := TIdHTTP.Create(nil);
     HTTP.ReadTimeout := 5000;
     ResultStr := TStringList.Create;
     ResultStr.Text := HTTP.Get('http://www.smsbao.com/query?u=wuhao13&p=0DB1E710BFDBE6317BE8B875804DF5A9');
     //判断返回值格式
     if (ResultStr.Strings[0] = '0') and (ResultStr.Count > 1) then
     begin
      //取出剩余条数
      match := TRegEx.Match(ResultStr.Strings[1], '([0-9]{1,8}),([0-9]*)');
      if match.Success then
      begin
        if match.Groups.Count >= 3 then
          Result := match.Groups.Item[2].Value;
      end;
     end;
  finally
    HTTP.Free;
  end;
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Action := caHide;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  FProcinstidLock := TIocpLocker.Create();
  UniPool := TUniDacAnyPool.Create(10);
  Form1.TrayIcon1.Visible := True;
  Form1.TrayIcon1.Animate := True;
  FPROCINSTID := TStringList.Create;
  //如果存在挂起列表则加载
  if FileExists(ExtractFilePath(ParamStr(0)) + 'list.ls') then
  begin
     FPROCINSTID.LoadFromFile(ExtractFilePath(ParamStr(0)) + 'list.ls');
  end;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  UniPool.Free;
  Form1.TrayIcon1.Visible := False;
  Form1.TrayIcon1.Animate := False;
  Workers.DisableWorkers;
  //保存挂起列表
  FPROCINSTID.SaveToFile(ExtractFilePath(ParamStr(0)) + 'list.ls');
  FPROCINSTID.Free;
  FProcinstidLock.Free;
end;


procedure TForm1.SendSmsTest(TaskName: string);
const
  SMSUser:string = '';
  SMSPassWord:string = '';
  PhoneNumber:string = '';      //
var
 // tmp_I:Integer;
//  SMSSTR:TStringList;
  LOG:string;
  HTTP:TIdHTTP;
  Md5Class:THashMD5;
begin
  try                                                                                                   //
   HTTP := TIdHTTP.Create(nil);
   HTTP.ReadTimeout := 20000;
   Md5Class := THashMD5.Create;
   HTTP.Get(Format('http://api.smsbao.com/sms?u=%s&p=%s&m=%s&c=%s',
                                                                  [SMSUser,
                                                                  Md5Class.GetHashString(SMSPassWord),
                                                                  PhoneNumber,
                                                                  HTTPEncode(UTF8Encode(TaskName))]));
  finally
   HTTP.Free;
  end;
end;

procedure TForm1.SendSmsTestNumber(Number: string);
begin

end;

function GetLastInput: DWORD; //得到电脑闲置时间
var
  LInput: TLastInputInfo;
  CurrTime: DWORD;
begin
  Result := 0;
  try
    LInput.cbSize := SizeOf(TLastInputInfo);
    GetLastInputInfo(LInput);
    CurrTime := GetTickCount;
      if CurrTime < LInput.dwTime then
        Exit;
    Result := Round((CurrTime - LInput.dwTime) / 1000);
  except
  end;
end;


function TForm1.SelectAssign(id: string): string;
const
  sql:string = 'select * from T_WFR_Assign where FPROCINSTID = ''%s''';
var
  Item:TItemUniOracle;
  UniQuery:TUniQuery;
begin
  Result := '';
  Item := UniPool.pop;
  UniQuery := Item.UniQuery;
  UniQuery.Active := False;
  UniQuery.SQL.Add(Format(sql,[id]));
  UniQuery.Active := True;
  UniQuery.First;
  if UniQuery.RecordCount = 1 then
    Result := UniQuery.Fields.FieldByName('FACTDEFNAME_L2').AsString


  else
  if UniQuery.RecordCount = 2 then
  begin
    Result := UniQuery.Fields.FieldByName('FACTDEFNAME_L2').AsString;
    UniQuery.Next;
    Result := Result + ',' + UniQuery.Fields.FieldByName('FACTDEFNAME_L2').AsString;
  end;
  UniQuery.Active := False;
  UniPool.push(Item);
end;

function TForm1.SelectUserFid(fid: string): string;
const
  sql:string = 'select FNAME_L1,FNAME_L2,FNAME_L3 from T_PM_User where fid =''%s''';
var
  Item:TItemUniOracle;
  UniQuery:TUniQuery;
begin
  Item := UniPool.pop;
  UniQuery := Item.UniQuery;
  UniQuery.Active := False;
  UniQuery.SQL.Add(Format(Sql,[fid]));
  UniQuery.Active := True;
  UniQuery.First;
  if NOT UniQuery.Eof then
  begin
    if UniQuery.RecordCount = 0 then
      Result := ''
    else
    begin
        Result := UniQuery.Fields.FieldByName('FNAME_L1').AsString;
        if Result = '' then
        Result := UniQuery.Fields.FieldByName('FNAME_L2').AsString;
        if Result = '' then
        Result := UniQuery.Fields.FieldByName('FNAME_L3').AsString;
    end;

  end;
  UniPool.push(Item);
end;

function TForm1.CheckWorkIsSuspended(id: string): Boolean;
const
   sql2:string = 'select FSTATE from EAS850.t_wfr_procinst T where (FPROCINSTID = ''%s'') and (FSTATE = ''open.not_running.suspended'')';
var
  Item:TItemUniOracle;
  UniQuery:TUniQuery;
begin
  Item := UniPool.pop;
  UniQuery := Item.UniQuery;
  UniQuery.Active := False;
  UniQuery.SQL.Add(Format(Sql2,[id]));
  UniQuery.Active := True;
  if UniQuery.RecordCount = 0 then
    Result := False
  else
    Result := True;

  UniPool.push(Item);
end;


procedure TForm1.CheckSuspendedList(AJob: PQJob);
var
   i: Integer;
begin
  //循环清理挂起列表中的流程
   FProcinstidLock.lock();
   for i := FPROCINSTID.Count - 1 downto 0 do
   begin
    if not CheckWorkIsSuspended(FPROCINSTID.Strings[i]) then
      FPROCINSTID.Delete(i);
   end;
   FProcinstidLock.unLock;
end;


procedure TForm1.FindSuspendedWorker(AJob: PQJob);
const
  Sql:string = 'select FCREATEDTIME,FCREATEDTIME,FPROCINSTID,FPROCINSTTOPIC_L1,FPPROCDEFNAME_L1,FINITIATORNAME_L1,FINITIATORID from EAS850.t_wfr_procinst T where (FSTATE = ''%s'') and ((FPROCDEFNAME_L1 like ''%s''));';

var
  tmp_I:Integer;
  Item:TItemUniOracle;
  UniQuery:TUniQuery;

begin
    Item := UniPool.pop;
    UniQuery := Item.UniQuery;

    UniQuery.Active := False;
    UniQuery.SQL.Clear;
    UniQuery.SQL.Add(Format(Sql,['open.not_running.suspended','xx集团%']));
    UniQuery.Active := True;
    UniQuery.First;
    while not UniQuery.Eof do
    begin
       if YearOf(UniQuery.Fields.FieldByName('FCREATEDTIME').AsDateTime) >= 2019 then
       begin
          FProcinstidLock.lock();
          if NOT FPROCINSTID.Find(UniQuery.Fields.FieldByName('FPROCINSTID').AsString,tmp_I) then
          begin
              FPROCINSTID.Add(UniQuery.Fields.FieldByName('FPROCINSTID').AsString);


              SendSmsTest(
                          Format('【EAS系统告警】发现新挂起流程，请及时处理，%s 发起人:%s',[UniQuery.Fields.FieldByName('FPROCINSTTOPIC_L1').AsString,
                                                                                            SelectUserFid(UniQuery.Fields.FieldByName('FINITIATORID').AsString),
                                                                                            SelectAssign(UniQuery.Fields.FieldByName('FPROCINSTID').AsString)]));
          end;
          FProcinstidLock.unLock;
       end;
       UniQuery.Next;
    end;
    UniPool.push(Item);
end;

procedure TForm1.FlushSmsNumberWorker(AJob: PQJob);
var
  R:string;
begin
   r := QuerySMSNumber;
   Form1.TrayIcon1.Hint := format('流程监控助手 短信余额:%s',[r]);
   form1.Caption := format('流程监控助手 短信余额:%s',[r]);
end;

//初始化用Time
procedure TForm1.tmr2Timer(Sender: TObject);
begin
  tmr2.Enabled := False;
  //初始化时查询余额
  Workers.Post(FlushSmsNumberWorker,nil,False);
  //提交定时查询余额任务 -- 每分钟一次
  Workers.Post(FlushSmsNumberWorker,60 * 10,nil,False);
  //查找挂起并通知管理员任务 -- 20秒一次
  Workers.Post(FindSuspendedWorker,20 * 10,nil,False);
  //检查挂起列表任务 -- 10秒一次
  Workers.Post(CheckSuspendedList,10 * 10,nil,False);
  //隐藏窗口
  Form1.Hide;
end;

procedure TForm1.TrayIcon1DblClick(Sender: TObject);
begin
  Form1.N1Click(nil);
end;

end.
